package com.ctbri.vSearch.controller;

import com.ctbri.vSearch.bean.dto.ArticleAndTermScore;
import com.ctbri.vSearch.bean.dto.SearchItem;
import com.ctbri.vSearch.bean.po.ArticleItem;
import com.ctbri.vSearch.bean.po.GzItem;
import com.ctbri.vSearch.bean.po.Link;
import com.ctbri.vSearch.bean.po.Node;
import com.ctbri.vSearch.bean.proto.LinkProto;
import com.ctbri.vSearch.bean.proto.NodeProto;
import com.ctbri.vSearch.dao.es.ScoreModel;
import com.ctbri.vSearch.dao.neo4j.Neo4jQueryDao;
import com.ctbri.vSearch.dao.neo4j.RelationMapQurey;
import com.ctbri.vSearch.frame.RedisPooledConnection;
import com.ctbri.vSearch.service.impl.DeepSearchServerImpl;
import com.ctbri.vSearch.util.TimeUtil;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Iterator;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import redis.clients.jedis.Jedis;

@Controller
public class BHController {

	private RedisPooledConnection rpc = null;

	@Resource
	DeepSearchServerImpl deepSearchServerImpl;

	@RequestMapping(value = "/search", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
	public String ulogin(HttpServletRequest request, Model model) throws IOException, SQLException {
		try {
			if (request.getParameter("word") == null || request.getParameter("word").equals("")) {
				System.out.println(request.getParameter("word"));
				return "search";
			}
			request.setCharacterEncoding("UTF-8");
			String word = request.getParameter("word");
			
			ObjectMapper mapper = new ObjectMapper();//?把neo4j的返回值转换为json格式
			List<String> nodes = new ArrayList<String>();
			List<String> links = new ArrayList<String>();
			String[] category = new String[1];//类型

			Map<String,Double> res = new HashMap<String,Double>();
			if(rpc == null){
				rpc = new RedisPooledConnection();
			}
			Jedis client = rpc.getClient();
			CountDownLatch countdownlatch = null;
			//判断是否redis中是否存在neo4j的查询结果
			// 命名规则：判断是否存在的标志：word+_neo4j
			// node: word+_node_neo4j
			// link: word+_link_neo4j
			TimeUtil timeutil = new TimeUtil();
			long start = timeutil.startTime();
			//获取连接并查询

			if(client.exists(word+"_neo4j")){
			//	client.del(word+"_neo4j"); //test
				//将缓存中的node取出，填充
				Iterator<String> iterNode=client.hkeys(word+"_node_neo4j").iterator();
				while (iterNode.hasNext()){
					String key = iterNode.next();
					ByteArrayInputStream input = new ByteArrayInputStream(client.hmget(word+"_node_neo4j", key).get(0).getBytes("ISO-8859-1"));
					NodeProto.Node nodeProto = NodeProto.Node.parseFrom(input);
					//判断是否为中心节点
					if(key.equals("0")){
						Node center = new Node();
						center.setCategory(nodeProto.getCategory());
						center.setLabel(word);
						center.setValue((double) 1);
						center.setName(word);
						String centerStr = mapper.writeValueAsString(center);
						nodes.add(centerStr);
					}
					else{
						Node node = new Node();
						node.setCategory(nodeProto.getCategory());
						node.setValue((double) 1);
						node.setName(nodeProto.getName());
						node.setLabel(nodeProto.getLabel());
						String nodeStr = mapper.writeValueAsString(node);
						nodes.add(nodeStr);
					}
				}
				//将缓存中的link取出，填充
				Iterator<String> iterLink=client.hkeys(word+"_link_neo4j").iterator();
				while (iterLink.hasNext()){
					String key = iterLink.next();
					ByteArrayInputStream input = new ByteArrayInputStream(client.hmget(word+"_link_neo4j", key).get(0).getBytes("ISO-8859-1"));
					LinkProto.Link linkProto = LinkProto.Link.parseFrom(input);
					Link link = new Link();
					String from = linkProto.getSource();
					link.setName(linkProto.getName());
					link.setSource(from);
					link.setTarget(linkProto.getTarget());
					link.setWeight((double) 2);
					String linkStr = mapper.writeValueAsString(link);
					links.add(linkStr);
					if(from.equals(word)){
						res.put(linkProto.getTarget(),linkProto.getWeight());
					}
				}
				res.put(word, 10.0);
				long end = timeutil.stopTime();
				System.out.println("从redis缓存中查询neo4j信息时间："+(end - start));
				System.out.println("从redis缓存中查找 "+word+" 完毕");

			}
			//redis中没有，即第一次查询某关键词时，从neo4j中查询，并存入redis中
			else {
				countdownlatch = new CountDownLatch(1);//同步控制器
				deepSearchServerImpl.searchRelationMap(countdownlatch, word, nodes, links, mapper, category,client);
				res = deepSearchServerImpl.searchRelatedWords(word);
				try {
					/**
					 * 在此等待“关系图”线程执行完毕
					 */
					countdownlatch.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				long end = timeutil.stopTime();
				System.out.println("直接从neo4j中查询信息时间："+(end - start));
			}
			/**
			 * 链接ES并做查询
			 */
			ArticleAndTermScore articleAndTermScore = new ArticleAndTermScore();
			deepSearchServerImpl.searchScoreModel(res,articleAndTermScore,rpc);


			//搜索词
			List<SearchItem> searchItems = new ArrayList<SearchItem>();
			//公众号
			List<GzItem> gzItems = new ArrayList<GzItem>();
			
			deepSearchServerImpl.dereplicationGzsAndArticles(searchItems, gzItems,articleAndTermScore);

			rpc.returnResource(client);

			model.addAttribute("title", word + "关系图谱");
			model.addAttribute("links", links.toString());
			model.addAttribute("nodes", nodes.toString());
			model.addAttribute("keyword", word);
			model.addAttribute("items", searchItems);
			model.addAttribute("gzitems", gzItems);
			if ("person".equals(category[0]) || "location".equals(category[0]) || "institution".equals(category[0])) {
				return "search_" + category[0];
			} else {
				return "search";
			}

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return "";
		}
	}

	@RequestMapping(value = "/")
	public String root() {
		return "index";
	}

	@RequestMapping(value = "/index")
	public String root2() {
		return "index";
	}

	@RequestMapping(value = "/graph")
	public String graph(HttpServletRequest request, Model model) {
		String word = request.getParameter("word");
		model.addAttribute("keyword", word);
		return "graph";
	}
}
